<?php

/**
 * @Project NUKEVIET
 * @Author VINADES.,JSC (contact@vinades.vn)
 * @Copyright (C) 2011 VINADES.,JSC. All rights reserved
 * @Createdate 18/10/2011, 9:45
 */

if ( ! defined( 'NV_MAINFILE' ) ) die( 'Stop!!!' );

/**
 * jdFromDate()
 * 
 * @param mixed $dd
 * @param mixed $mm
 * @param mixed $yy
 * @return
 */
function jdFromDate( $dd, $mm, $yy )
{
    $a = floor( ( 14 - $mm ) / 12 );
    $y = $yy + 4800 - $a;
    $m = $mm + 12 * $a - 3;
    $jd = $dd + floor( ( 153 * $m + 2 ) / 5 ) + 365 * $y + floor( $y / 4 ) - floor( $y / 100 ) + floor( $y / 400 ) - 32045;
    if ( $jd < 2299161 )
    {
        $jd = $dd + floor( ( 153 * $m + 2 ) / 5 ) + 365 * $y + floor( $y / 4 ) - 32083;
    }
    return $jd;
}

/**
 * jdToDate()
 * 
 * @param mixed $jd
 * @return
 */
function jdToDate( $jd )
{
    if ( $jd > 2299160 )
    {

        $a = $jd + 32044;
        $b = floor( ( 4 * $a + 3 ) / 146097 );
        $c = $a - floor( ( $b * 146097 ) / 4 );
    }
    else
    {
        $b = 0;
        $c = $jd + 32082;
    }
    $d = floor( ( 4 * $c + 3 ) / 1461 );
    $e = $c - floor( ( 1461 * $d ) / 4 );
    $m = floor( ( 5 * $e + 2 ) / 153 );
    $day = $e - floor( ( 153 * $m + 2 ) / 5 ) + 1;
    $month = $m + 3 - 12 * floor( $m / 10 );
    $year = $b * 100 + $d - 4800 + floor( $m / 10 );

    return array( $day, $month, $year );
}

/**
 * getNewMoonDay()
 * 
 * @param mixed $k
 * @param mixed $timeZone
 * @return
 */
function getNewMoonDay( $k, $timeZone )
{
    $T = $k / 1236.85;

    $T2 = $T * $T;
    $T3 = $T2 * $T;
    $dr = M_PI / 180;
    $Jd1 = 2415020.75933 + 29.53058868 * $k + 0.0001178 * $T2 - 0.000000155 * $T3;
    $Jd1 = $Jd1 + 0.00033 * sin( ( 166.56 + 132.87 * $T - 0.009173 * $T2 ) * $dr );

    $M = 359.2242 + 29.10535608 * $k - 0.0000333 * $T2 - 0.00000347 * $T3;

    $Mpr = 306.0253 + 385.81691806 * $k + 0.0107306 * $T2 + 0.00001236 * $T3;

    $F = 21.2964 + 390.67050646 * $k - 0.0016528 * $T2 - 0.00000239 * $T3;

    $C1 = ( 0.1734 - 0.000393 * $T ) * sin( $M * $dr ) + 0.0021 * sin( 2 * $dr * $M );
    $C1 = $C1 - 0.4068 * sin( $Mpr * $dr ) + 0.0161 * sin( $dr * 2 * $Mpr );
    $C1 = $C1 - 0.0004 * sin( $dr * 3 * $Mpr );
    $C1 = $C1 + 0.0104 * sin( $dr * 2 * $F ) - 0.0051 * sin( $dr * ( $M + $Mpr ) );
    $C1 = $C1 - 0.0074 * sin( $dr * ( $M - $Mpr ) ) + 0.0004 * sin( $dr * ( 2 * $F + $M ) );
    $C1 = $C1 - 0.0004 * sin( $dr * ( 2 * $F - $M ) ) - 0.0006 * sin( $dr * ( 2 * $F + $Mpr ) );
    $C1 = $C1 + 0.0010 * sin( $dr * ( 2 * $F - $Mpr ) ) + 0.0005 * sin( $dr * ( 2 * $Mpr + $M ) );
    if ( $T < -11 )
    {
        $deltat = 0.001 + 0.000839 * $T + 0.0002261 * $T2 - 0.00000845 * $T3 - 0.000000081 * $T * $T3;
    }
    else
    {
        $deltat = -0.000278 + 0.000265 * $T + 0.000262 * $T2;
    }
    ;
    $JdNew = $Jd1 + $C1 - $deltat;

    return floor( $JdNew + 0.5 + $timeZone / 24 );
}

/**
 * getSunLongitude()
 * 
 * @param mixed $jdn
 * @param mixed $timeZone
 * @return
 */
function getSunLongitude( $jdn, $timeZone )
{
    $T = ( $jdn - 2451545.5 - $timeZone / 24 ) / 36525;

    $T2 = $T * $T;
    $dr = M_PI / 180;

    $M = 357.52910 + 35999.05030 * $T - 0.0001559 * $T2 - 0.00000048 * $T * $T2;

    $L0 = 280.46645 + 36000.76983 * $T + 0.0003032 * $T2;

    $DL = ( 1.914600 - 0.004817 * $T - 0.000014 * $T2 ) * sin( $dr * $M );
    $DL = $DL + ( 0.019993 - 0.000101 * $T ) * sin( $dr * 2 * $M ) + 0.000290 * sin( $dr * 3 * $M );
    $L = $L0 + $DL;


    $L = $L * $dr;
    $L = $L - M_PI * 2 * ( floor( $L / ( M_PI * 2 ) ) );

    return floor( $L / M_PI * 6 );
}

/**
 * getLunarMonth11()
 * 
 * @param mixed $yy
 * @param mixed $timeZone
 * @return
 */
function getLunarMonth11( $yy, $timeZone )
{
    $off = jdFromDate( 31, 12, $yy ) - 2415021;
    $k = floor( $off / 29.530588853 );
    $nm = getNewMoonDay( $k, $timeZone );
    $sunLong = getSunLongitude( $nm, $timeZone );

    if ( $sunLong >= 9 )
    {
        $nm = getNewMoonDay( $k - 1, $timeZone );
    }
    return $nm;
}

/**
 * getLeapMonthOffset()
 * 
 * @param mixed $a11
 * @param mixed $timeZone
 * @return
 */
function getLeapMonthOffset( $a11, $timeZone )
{
    $k = floor( ( $a11 - 2415021.076998695 ) / 29.530588853 + 0.5 );
    $last = 0;
    $i = 1;

    $arc = getSunLongitude( getNewMoonDay( $k + $i, $timeZone ), $timeZone );
    do
    {
        $last = $arc;
        $i = $i + 1;
        $arc = getSunLongitude( getNewMoonDay( $k + $i, $timeZone ), $timeZone );
    } while ( $arc != $last && $i < 14 );
    return $i - 1;
}


/**
 * convertSolar2Lunar()
 * 
 * @param mixed $dd
 * @param mixed $mm
 * @param mixed $yy
 * @param mixed $timeZone
 * @return
 */
function convertSolar2Lunar( $dd, $mm, $yy, $timeZone )
{
    $dayNumber = jdFromDate( $dd, $mm, $yy );
    $k = floor( ( $dayNumber - 2415021.076998695 ) / 29.530588853 );
    $monthStart = getNewMoonDay( $k + 1, $timeZone );
    if ( $monthStart > $dayNumber )
    {
        $monthStart = getNewMoonDay( $k, $timeZone );
    }
    $a11 = getLunarMonth11( $yy, $timeZone );
    $b11 = $a11;
    if ( $a11 >= $monthStart )
    {
        $lunarYear = $yy;
        $a11 = getLunarMonth11( $yy - 1, $timeZone );
    }
    else
    {
        $lunarYear = $yy + 1;
        $b11 = getLunarMonth11( $yy + 1, $timeZone );
    }
    $lunarDay = $dayNumber - $monthStart + 1;
    $diff = floor( ( $monthStart - $a11 ) / 29 );
    $lunarLeap = 0;
    $lunarMonth = $diff + 11;
    if ( $b11 - $a11 > 365 )
    {
        $leapMonthDiff = getLeapMonthOffset( $a11, $timeZone );
        if ( $diff >= $leapMonthDiff )
        {
            $lunarMonth = $diff + 10;
            if ( $diff == $leapMonthDiff )
            {
                $lunarLeap = 1;
            }
        }
    }
    if ( $lunarMonth > 12 )
    {
        $lunarMonth = $lunarMonth - 12;
    }
    if ( $lunarMonth >= 11 && $diff < 4 )
    {
        $lunarYear -= 1;
    }
    return array( $lunarDay, $lunarMonth, $lunarYear, $lunarLeap );
}


/**
 * convertLunar2Solar()
 * 
 * @param mixed $lunarDay
 * @param mixed $lunarMonth
 * @param mixed $lunarYear
 * @param mixed $lunarLeap
 * @param mixed $timeZone
 * @return
 */
function convertLunar2Solar( $lunarDay, $lunarMonth, $lunarYear, $lunarLeap, $timeZone )
{
    if ( $lunarMonth < 11 )
    {
        $a11 = getLunarMonth11( $lunarYear - 1, $timeZone );
        $b11 = getLunarMonth11( $lunarYear, $timeZone );
    }
    else
    {
        $a11 = getLunarMonth11( $lunarYear, $timeZone );
        $b11 = getLunarMonth11( $lunarYear + 1, $timeZone );
    }
    $k = floor( 0.5 + ( $a11 - 2415021.076998695 ) / 29.530588853 );
    $off = $lunarMonth - 11;
    if ( $off < 0 )
    {
        $off += 12;
    }
    if ( $b11 - $a11 > 365 )
    {
        $leapOff = getLeapMonthOffset( $a11, $timeZone );
        $leapMonth = $leapOff - 2;
        if ( $leapMonth < 0 )
        {
            $leapMonth += 12;
        }
        if ( $lunarLeap != 0 && $lunarMonth != $leapMonth )
        {
            return array( 0, 0, 0 );
        }
        else
            if ( $lunarLeap != 0 || $off >= $leapOff )
            {
                $off += 1;
            }
    }
    $monthStart = getNewMoonDay( $k + $off, $timeZone );
    return jdToDate( $monthStart + $lunarDay - 1 );
}

/**
 * alhn()
 * 
 * @return
 */
function alhn()
{
    $CAN = array( "Giáp", "Ất", "Bính", "Đinh", "Mậu", "Kỷ", "Canh", "Tân", "Nhâm", "Quý" );
    $CHI = array( "Tý", "Sửu", "Dần", "Mão", "Thìn", "Tỵ", "Ngọ", "Mùi", "Thân", "Dậu", "Tuất", "Hợi" );
    $arr = array_slice( convertSolar2Lunar( date( 'd' ), date( 'm' ), date( 'Y' ), 7 ), 0, 3 );
    $arr[0] = str_pad( $arr[0], 2, '0', STR_PAD_LEFT );
    $arr[1] = str_pad( $arr[1], 2, '0', STR_PAD_LEFT );
    $arr[2] = $CAN[( $arr[2] + 6 ) % 10] . " " . $CHI[( $arr[2] + 8 ) % 12];
    return "Âm lịch: ngày " . $arr[0] . " tháng " . $arr[1] . " năm " . $arr[2];
}

?>